using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Wrath.Windows.Forms;
using Wrath.Xml;
using Wrath.Xml.Objects;
using System.IO;
using Wrath.RuleForge.Property;

using System.Diagnostics;
using Wrath.CodeBox;

namespace Wrath.RuleForge.Imaging
{
  public partial class CustomDieEditor : DockContent, Interfaces.ICanUndo, Interfaces.ICanSave
  {
    private Element sourceElement;
    private string name = "";
    private string icon = "";
    private string model = "";
    private string script = "";
    private bool undoable = false;

    public CustomDieEditor(Element dieElement)
    {
      Wrath.Xml.Attribute attribute;
      Element element;

      InitializeComponent();

      // Set the scriptBox event handlers
      scriptBox.GotFocus += new System.EventHandler(scriptBox_GotFocus);
      scriptBox.LostFocus += new System.EventHandler(scriptBox_LostFocus);

      sourceElement = dieElement;

      if (dieElement != null)
      {
        if ((attribute = dieElement.FindAttribute("name")) != null)
          name = attribute.Value;

        if ((element = dieElement.FindFirstElement("menuicon", false)) != null)
          icon = element.Value;

        if ((element = dieElement.FindFirstElement("model", false)) != null)
          model = element.Value;

        if ((element = dieElement.FindFirstElement("script", false)) != null)
          script = element.Value;
      }

    }

    private void CustomDieEditor_Load(object sender, EventArgs e)
    {
      textBoxName.Text = name;
      this.TabText = textBoxName.Text + "  ";
      setComboValue(comboBoxModel, model);
      // Load the icon names from the CurrentRuleSet.Icons collection
      foreach (KeyValuePair<string, Wrath.Xml.Element> kvp in CurrentRuleSet.Icons)
      {
        comboBoxIconName.Items.Add(kvp.Key);
      }
      setComboValue(comboBoxIconName, icon);
      // fetch the icon
      RefreshIcon();
      // create a script parser
      scriptBox.Parser = new LanguageParser();
      scriptBox.Parser.Language.Xml = global::Wrath.RuleForge.Properties.Resources.LuaDefInline;
      // load the script content
      scriptBox.Text = script;
      // set the focus to the name box
      textBoxName.Focus();
      // start responding to Undos
      undoable = true;
    }

    private void RefreshIcon()
    {
      Element iconvalue;
      string filePath = "";
      string iconname = getComboValue(comboBoxIconName);

      // Fetch the icon element from the current ruleset
      if (CurrentRuleSet.Icons.TryGetValue(iconname, out iconvalue))
      { // Found the icon, display it
        Wrath.Xml.Attribute source = iconvalue.FindAttribute("file");
        if (source != null)
        {
          filePath = CurrentRuleSet.Path + "\\" + source.Value.Replace("/", "\\");
          pictureBoxIcon.Load(filePath);
        }
      }
      if (filePath == "")
      { // Unrecognised icon, show a placeholder
        pictureBoxIcon.Image = pictureBoxIcon.ErrorImage;
      }
    }

    #region ICanUndo Members

    private Stack<PropertyUndoData> undoData = new Stack<PropertyUndoData>(0);

    [Browsable(false)]
    public bool UndoEnabled
    {
      get { return (undoData.Count > 0); }
    }

    public void Undo()
    {
      // Do some undo stuffs.
      if (UndoEnabled)
      {
        PropertyUndoData data = undoData.Pop();

        // prevent the action being pushed onto the undo stack
        undoable = false;

        switch (data.Name)
        {
          case "Name":
            textBoxName.Text = data.Value;
            name = data.Value;
            break;
          case "Model":
            setComboValue(comboBoxModel, data.Value);
            model = data.Value;
            break;
          case "Icon":
            setComboValue(comboBoxIconName, data.Value);
            icon = data.Value;
            RefreshIcon();
            break;
          case "Script":
            //textBoxScript.Text = data.Value;
            script = data.Value;
            break;
        }

        // resume undoability
        undoable = true;

      }

      toolStripButtonUndo.Enabled = UndoEnabled;
      toolStripButtonSave.Enabled = UndoEnabled;

      this.Refresh();
    }

    private void CreateUndoData(string name, string value)
    {
      PropertyUndoData data = new PropertyUndoData(name, value);

      // Add this to the undo stack.
      undoData.Push(data);

      // set the save icon
      toolStripButtonSave.Enabled = true;
      toolStripButtonUndo.Enabled = true;
    }

    #endregion

    #region ICanSave Members

    public void Save()
    {
      if (UndoEnabled)
      {
        // Transfer values to the underlying element.
        Element element;
        Wrath.Xml.Attribute attribute;

        if ((attribute = sourceElement.FindAttribute("name")) == null)
        {
          attribute = new Wrath.Xml.Attribute();
          attribute.Name = "name";
          sourceElement.Attributes.Add(attribute);
        }
        attribute.Value = name;

        if ((element = sourceElement.FindFirstElement("model", false)) == null)
        {
          element = new Element();
          element.Name = "model";
          sourceElement.ChildElements.Add(element);
        }
        element.Value = model;

        if ((element = sourceElement.FindFirstElement("script", false)) == null)
        {
          element = new Element();
          element.Name = "script";
          sourceElement.ChildElements.Add(element);
        }
        element.Value = script;

        if ((element = sourceElement.FindFirstElement("menuicon", false)) == null)
        {
          element = new Element();
          element.Name = "menuicon";
          sourceElement.ChildElements.Add(element);
        }
        element.Value = icon;

        EventBroker.FireElementPropertyChanged(sourceElement);

        undoData.Clear();
        undoData.TrimExcess();

        toolStripButtonUndo.Enabled = UndoEnabled;
        toolStripButtonSave.Enabled = UndoEnabled;

      }
    }

    #endregion

    private void Control_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.Modifiers == Keys.Control)
      {
        if (e.KeyCode == Keys.Z)
        {
          Undo();
        }
        else if (e.KeyCode == Keys.S)
        {
          Save();
        }
      }
    }

    private void toolStripButtonSave_Click(object sender, EventArgs e)
    {
      Save();
    }

    private void toolStripButtonUndo_Click(object sender, EventArgs e)
    {
      Undo();
    }

    private void CustomDieEditor_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (UndoEnabled)
      {
        DialogResult result = MessageBox.Show("This Custom Die Definition has been modified. Do you want to save the changes?", "Save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation);
        if (result != DialogResult.No)
        {
          if (result == DialogResult.Yes)
          {
            Save();
          }
          else if (result == DialogResult.Cancel)
          {
            e.Cancel = true;
          }
        }
      }
    }

    private void textBoxName_TextChanged(object sender, EventArgs e)
    {
      if (undoable)
       CreateUndoData("Name", name);
      name = textBoxName.Text;
      this.TabText = textBoxName.Text + "  ";
    }

    private void textBoxName_GotFocus(object sender, EventArgs e)
    {
      setHelpText("Name");
    }

    private void textBoxName_LostFocus(object sender, EventArgs e)
    {
      labelHelp.Text = "";
    }

    private void comboBoxModel_SelectedIndexChanged(object sender, EventArgs e)
    {
      if (undoable)
        CreateUndoData("Model", model);
      model = getComboValue(comboBoxModel);
    }

    private void comboBoxModel_GotFocus(object sender, EventArgs e)
    {
      setHelpText("Model");
    }

    private void comboBoxModel_LostFocus(object sender, EventArgs e)
    {
      labelHelp.Text = "";
    }

    private void comboBoxIconName_TextChanged(object sender, EventArgs e)
    {
      if (undoable)
        CreateUndoData("Icon", icon);
      icon = getComboValue(comboBoxIconName);

      RefreshIcon();
    }

    private void comboBoxIconName_GotFocus(object sender, EventArgs e)
    {
      setHelpText("Icon");
    }

    private void comboBoxIconName_LostFocus(object sender, EventArgs e)
    {
      labelHelp.Text = "";
    }

    private void scriptBox_GotFocus(object sender, EventArgs e)
    {
      Debug.WriteLine("scriptBox GotFocus()");
      setHelpText("Script");
    }

    private void scriptBox_LostFocus(object sender, EventArgs e)
    {
      Debug.WriteLine("scriptBox LostFocus()");
      labelHelp.Text = "";
    }

    private void setHelpText(string property)
    {
      CustomDieWrapper wrapper = new CustomDieWrapper(sourceElement);

      // Fetch the description attribute from the Wrapper
      AttributeCollection attributes = TypeDescriptor.GetProperties(wrapper)[property].Attributes;
      DescriptionAttribute myAttribute = (DescriptionAttribute)attributes[typeof(DescriptionAttribute)];

      // Display the description in the status bar
      labelHelp.Text = myAttribute.Description;
    }

    private void setComboValue(ComboBox combo, string Value)
    {
      if (combo.DropDownStyle == ComboBoxStyle.DropDownList)
      { // set the selected item
        combo.SelectedIndex = combo.Items.IndexOf(Value);
        combo.Select();
      }
      else
      { // set the editable text
        combo.Text = Value;
        combo.SelectAll();
      }
    }

    private string getComboValue(ComboBox combo)
    {
      if (combo.DropDownStyle == ComboBoxStyle.DropDownList)
      { // fetch the selected item
        if (combo.SelectedIndex < 0)
          return "";
        return combo.SelectedItem.ToString();
      }
      else
      { // fetch the editable text
        return combo.Text;
      }
    }

    private void toolStripButtonScript_Click(object sender, EventArgs e)
    {
      toolStripButtonScript.Checked = !toolStripButtonScript.Checked;
      scriptBox.Visible = toolStripButtonScript.Checked;
      panelDetails.Visible = !toolStripButtonScript.Checked;
      if (scriptBox.Visible)
        scriptBox.Focus();
      else
        panelDetails.Focus();
    }

  }
}